package com.apes.fn.scm.lossSale;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.business.fixedLoss.modle.LossQuotation;
import com.apes.fn.business.fixedLoss.repository.LossQuotationRepository;
import com.apes.fn.business.fixedLoss.service.LossReceivedApportionService;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.repository.RetailOrderRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.BaseModel;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.esb.processor.idempotent.AntiHeavy;
import com.apes.framework.plugin.esb.processor.idempotent.AntiHeavyRepository;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.Tools;
import com.apes.scm.sal.saleOrder.SaleOrder;
import com.apes.scm.sal.saleOrder.SaleOrderRepository;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.repository.VoucherRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author wuq
 * @Date 2021-12-8
 */
@Service
public class LossSaleAdjustReturnService extends DomainService {

    @Autowired
    private LossSaleAdjustRepository lossSaleAdjustRepository;
    @Autowired
    private RetailOrderRepository retailOrderRepository;
    @Autowired
    private InsuranceSaleReturnService insuranceSaleReturnService;
    @Autowired
    private InsuranceSaleCostReturnService insuranceSaleCostReturnService;
    @Autowired
    private LossSaleAdjustDao lossSaleAdjustDao;
    @Autowired
    private LossQuotationRepository lossQuotationRepository;

    public LossSaleAdjust save(SimpleRequest request) {
        JSONObject json = request.getJO();
        json.remove("referenceAccounts");
        LossSaleAdjust lossSaleAdjust = Tools.map(json, LossSaleAdjust.class);
        if (StringUtils.isEmpty(lossSaleAdjust.getRetailId())) throw new RuntimeException("零售单号为空，请检查！");

        // 数据检查，不能多次调整，第一次调整是原始销售；第二次调整是需要查当前的 LossSaleAdjust，逻辑不一样
        ArrayList rows = new ArrayList();
        rows.add(MapUtil.mapper("field", "retailId", "operator", "EQ", "value", lossSaleAdjust.getRetailId()));
        rows.add(MapUtil.mapper("field", "state", "operator", "NE", "value", "delete"));

        List<LossSaleAdjust> list = lossSaleAdjustRepository.findAll(JpaDsl.toCriteria(rows));
        if (!list.isEmpty()) throw new RuntimeException("该零售单已经做过调整，不能二次调整");

        // 零售单数据检查
        RetailOrder retailOrder = findRetailOrder(lossSaleAdjust.getRetailId());

        lossSaleAdjust.setState("sent");
        lossSaleAdjust.setCreator(request.getPersonId());
        lossSaleAdjust.setCreateDate(new Date());
        lossSaleAdjust.setCompany(lossSaleAdjust.getDept().getCompany());

        lossSaleAdjust.setCustomerExpand(retailOrder.getCustomerExpand());
        return lossSaleAdjustRepository.saveAndFlush(lossSaleAdjust);
    }

    public LossSaleAdjust update(SimpleRequest request) {
        JSONObject json = request.getJO();
        json.remove("referenceAccounts");

        LossSaleAdjust lossSaleAdjust = Tools.map(json, LossSaleAdjust.class);
        return lossSaleAdjustRepository.saveAndFlush(lossSaleAdjust);
    }

    private RetailOrder findRetailOrder(String retailId) {
        RetailOrder retailOrder = retailOrderRepository.findOne(retailId);
        if (retailId == null) throw new RuntimeException("没有找到【" + retailId + "】对应的零售单");
        if (retailOrder.getScene() == null || !"RO002".equals(retailOrder.getScene().getId())) {
            throw new RuntimeException("非赋能定损销售来源的单据，不允许调整");
        }
        return retailOrder;
    }

    public String delete(SimpleRequest request) {
        JSONObject json = request.getJO();
        json.remove("referenceAccounts");
        LossSaleAdjust lossSaleAdjust = Tools.map(json, LossSaleAdjust.class);

        lossSaleAdjust.setDeleteId(request.getPerson());
        lossSaleAdjust.setDeleteDate(new Date());
        lossSaleAdjust.setState("delete");
        lossSaleAdjustRepository.saveAndFlush(lossSaleAdjust);
        return "删除成功";
    }

    /**
     * 根据零售单获取分销单、分销单凭证数据
     *
     * @param request lossQuotationId
     * @return Map
     */
    public Map findOriginOrder(SimpleRequest request) {
        // 获取零售单
        RetailOrder retailOrder = findRetailOrder(request.get("retailId"));

        Map<String, Object> result = new HashMap<>();
        result.put("dept", MapUtil.mapped(retailOrder.getServiceDept()));
        result.put("getCarDept", MapUtil.mapped(retailOrder.getGetCarDept()));
        result.put("lossQuotationId", retailOrder.getSource());
        result.put("customerExpand", MapUtil.mapped(retailOrder.getCustomerExpand()));
        result.put("oldInsuranceCompany", MapUtil.mapped(retailOrder.getInsuranceCompany()));
        result.put("referenceAccounts", findReferenceAccounts(retailOrder.getId()));    // 查询相关账目明细
        return result;
    }

    public List<LossSaleAdjustAccounts> findReferenceAccounts(String retailId) {
        List<LossSaleAdjustAccounts> mapList = new ArrayList<>();

        // 查询分销单
        List<SaleOrder> saleOrders = SpringManager.getBean(SaleOrderRepository.class).findAllBySource(retailId);
        saleOrders.forEach(saleOrder -> {

            LossSaleAdjustAccounts lossSaleAdjustAccounts = new LossSaleAdjustAccounts();
            lossSaleAdjustAccounts.setOrderType("分销单");
            lossSaleAdjustAccounts.setOrderId(saleOrder.getId());
            lossSaleAdjustAccounts.setCompany(MapUtil.mapped(saleOrder.getCompany()));
            lossSaleAdjustAccounts.setPartner(MapUtil.mapped(saleOrder.getCustomer()));
            lossSaleAdjustAccounts.setVoucherType("");
            lossSaleAdjustAccounts.setAmount(saleOrder.getAmtTotal());

            mapList.add(lossSaleAdjustAccounts);
        });

        // 查询凭证 直接对保险公司销售部分
        ArrayList saleRow = new ArrayList();
        saleRow.add(MapUtil.mapper("field", "source", "operator", "IN", "value", saleOrders.stream().map(SaleOrder::getId).collect(Collectors.toList())));
        List<Voucher> vouchers = SpringManager.getBean(VoucherRepository.class).findAll(JpaDsl.toCriteria(saleRow));
        vouchers.stream().sorted(Comparator.comparing(BaseModel::getCreateDate))
                .forEach(voucher -> {

                    LossSaleAdjustAccounts lossSaleAdjustAccounts = new LossSaleAdjustAccounts();
                    lossSaleAdjustAccounts.setOrderType("业务凭证");
                    lossSaleAdjustAccounts.setOrderId(voucher.getId());
                    lossSaleAdjustAccounts.setCompany(MapUtil.mapped(voucher.getCompany()));
                    lossSaleAdjustAccounts.setPartner(MapUtil.mapped(voucher.getPartner()));
                    lossSaleAdjustAccounts.setVoucherType("SUPPLIER_PURCHASE".equals(voucher.getVoucherType()) ? "采购凭证" : "销售凭证");
                    lossSaleAdjustAccounts.setAmount(voucher.getAmtTotal());

                    mapList.add(lossSaleAdjustAccounts);
                });

        // 跨公司对保险公司销售部分
        List<Voucher> retailVoucher = SpringManager.getBean(VoucherRepository.class).findAll(JpaDsl.toCriteriaByEq("source", retailId));
        retailVoucher.stream().sorted(Comparator.comparing(BaseModel::getCreateDate))
                .forEach(voucher -> {

                    LossSaleAdjustAccounts lossSaleAdjustAccounts = new LossSaleAdjustAccounts();
                    lossSaleAdjustAccounts.setOrderType("业务凭证");
                    lossSaleAdjustAccounts.setOrderId(voucher.getId());
                    lossSaleAdjustAccounts.setCompany(MapUtil.mapped(voucher.getCompany()));
                    lossSaleAdjustAccounts.setPartner(MapUtil.mapped(voucher.getPartner()));
                    lossSaleAdjustAccounts.setVoucherType("SUPPLIER_PURCHASE".equals(voucher.getVoucherType()) ? "采购凭证" : "销售凭证");
                    lossSaleAdjustAccounts.setAmount(voucher.getAmtTotal());

                    mapList.add(lossSaleAdjustAccounts);
                });
        return mapList;
    }


    public LossSaleAdjust confirm(SimpleRequest request) {
        String id = request.get("id");
        LossSaleAdjust lossSaleAdjust = lossSaleAdjustRepository.findOne(id);

        lossSaleAdjust.setConfirmId(request.getPerson());
        lossSaleAdjust.setConfirmDate(new Date());
        lossSaleAdjust.setState("confirm");

        return lossSaleAdjustRepository.saveAndFlush(lossSaleAdjust);
    }

    /**
     * 回退到创建状态
     *
     * @param request
     * @return
     */
    public Object goBack(SimpleRequest request) {
        LossSaleAdjust lossSaleAdjust = request.getO(LossSaleAdjust.class);
        lossSaleAdjust.setState("sent");
        LossSaleAdjust result = lossSaleAdjustRepository.saveAndFlush(lossSaleAdjust);
        goBackLogger(result);
        return MapUtil.mapped(result);
    }

    private void goBackLogger(LossSaleAdjust lossSaleAdjust) {
        this.sendSynEvent("event:ir.logger.create",
                MapUtil.mapper(
                        "businessType", lossSaleAdjust.getInnerBusinessType(),
                        "businessKey", lossSaleAdjust.getInnerBusinessKey(),
                        "operate", "退回",
                        "remark", lossSaleAdjust.getGoBackRemark())
        );
    }

    public LossSaleAdjust approve(SimpleRequest request) {
        LossSaleAdjust lossSaleAdjust = request.getO(LossSaleAdjust.class);
        LossSaleAdjust oldLossSaleAdjust = lossSaleAdjustRepository.findOne(lossSaleAdjust.getId());

        // 数据检查
        if (lossSaleAdjust.getVersion() != oldLossSaleAdjust.getVersion()) {
            throw new RuntimeException("提交数据有误，请刷新界面后提交");
        }

        // 增加幂等控制，数据库建议唯一索引
        AntiHeavy antiHeavy = new AntiHeavy();
        antiHeavy.setId("lossSale.return.approve:" + oldLossSaleAdjust.getId());
        SpringManager.getBean(AntiHeavyRepository.class).save(antiHeavy);

        oldLossSaleAdjust.setApproveUID(request.getPerson());
        oldLossSaleAdjust.setDateApprove(new Date());
        oldLossSaleAdjust.setState("approve");

        oldLossSaleAdjust = lossSaleAdjustRepository.saveAndFlush(oldLossSaleAdjust);

        // 账目处理
        voucher(oldLossSaleAdjust);

        //回写至定损单并更新到账状态
        writeToLossQuotation(oldLossSaleAdjust);

        return oldLossSaleAdjust;
    }

    /**
     * 账目调整处理
     *
     * @param lossSaleAdjust LossSaleAdjust
     */
    private void voucher(LossSaleAdjust lossSaleAdjust) {
        // 退保险公司销售以及重新对保险公司销售
        if (lossSaleAdjust.getOriginalAmount() == lossSaleAdjust.getAmount() && "adjustReason03".equals(lossSaleAdjust.getLossAdjustReason().getId())) {
            // 保险公司错误，并且调整金额相同： 通过原销售商品退
            insuranceSaleCostReturnService.process(lossSaleAdjust);
        } else {
            // 通过挂账商品退
            insuranceSaleReturnService.process(lossSaleAdjust);
        }
    }

    /**
     * 回写调整金额至定损单并更新到账状态
     *
     * @param lossSaleAdjust
     */
    private void writeToLossQuotation(LossSaleAdjust lossSaleAdjust) {
        String lossQuotationId = lossSaleAdjust.getLossQuotationId();
        LossQuotation lossQuotation = lossQuotationRepository.findOne(lossQuotationId);
        lossQuotation.setAdjustAmount(lossSaleAdjust.getAdjustAmount());
        SpringManager.getBean(LossReceivedApportionService.class).lossSaleAdjustCreateLossApportion(lossSaleAdjust);
        //更新到账状态
        lossQuotation.updateReceivedState();

        lossQuotationRepository.saveAndFlush(lossQuotation);
    }

    public void test(SimpleRequest request) {
        String id = request.get("id");
        LossSaleAdjust lossSaleAdjust = lossSaleAdjustRepository.findOne(id);

        voucher(lossSaleAdjust);
//        int a = 1/0;
//        writeToLossQuotation(lossSaleAdjust);
    }

    private Object filter(SimpleRequest request) {
        JSONObject json = request.getJO();
        json.remove("referenceAccounts");
        LossSaleAdjust lossSaleAdjust = Tools.map(json, LossSaleAdjust.class);
        if (lossSaleAdjust.getAmount() <= 0) throw new RuntimeException("保存失败，调整后金额不能小于等于0！");
        return request.getJO();
    }

    public Object pageFindAll(SimpleRequest request) {
        JSONObject jo = request.getJO();
        JSONArray conditions = jo.getJSONArray("condition");
        JSONObject param = new JSONObject();
        for (Object item : conditions) {
            JSONObject condition = (JSONObject) item;
            String field = condition.getString("field");
            String value = condition.getString("value");
            if (condition.containsKey("type") && condition.getString("type").equals("date")) {
                String operator = condition.getString("operator");
                param.put(field + operator, value);
            }
            param.put(field, value);
        }
        // 查询并分页
        Pageable pageable = PageRequest.of(request.get("page"), request.get("size"));
        int min = pageable.getPageSize() * pageable.getPageNumber();
        int max = pageable.getPageSize() * (pageable.getPageNumber() + 1);
        param.put("min", min);
        param.put("max", max);
        // 查询数据
        JSONArray allJA = lossSaleAdjustDao.lossSaleAdjustFindAll(param);
        JSONArray countJA = lossSaleAdjustDao.lossSaleAdjustFindAllCount(param);
        Integer count = countJA.getJSONObject(0).getInteger("COUNT");
        List<String> ids = allJA.stream().map(item -> ((JSONObject) item).getString("ID")).collect(Collectors.toList());
        List<LossSaleAdjust> current = new ArrayList<>();
        if (!ids.isEmpty()) current = lossSaleAdjustRepository.findAll(JpaDsl.toCriteria("id", "in", ids));
        // 分页
        return new PageImpl<>(current, pageable, count);
    }
}
